package com.capgemini.cn.authority.rest.service.impl;

import com.capgemini.cn.authority.data.entity.Groups;
import com.capgemini.cn.authority.data.entity.Roles;
import com.capgemini.cn.authority.data.repository.GroupsRepository;
import com.capgemini.cn.authority.data.repository.RolesRepository;
import com.capgemini.cn.authority.rest.exception.AuthRestBusinessException;
import com.capgemini.cn.authority.rest.service.AbstractBaseService;
import com.capgemini.cn.authority.rest.service.RoleService;
import com.capgemini.cn.authority.rest.valueobject.DataPage;
import com.capgemini.cn.authority.rest.valueobject.DataResponse;
import com.capgemini.cn.authority.rest.valueobject.data.RoleVO;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Created at 2017/9/18
 *
 * @author Andriy
 */
@Service(value = RoleServiceImpl.COMPONENT_NAME)
public class RoleServiceImpl extends AbstractBaseService<RoleVO, Roles> implements RoleService {

    public static final String COMPONENT_NAME = "roleService";

    protected final String[] IGNORE_PROPERTIES = {
            "groupsList",
            "authorities"
    };

    @Autowired
    @Getter(value = AccessLevel.PROTECTED)
    @Setter
    private RolesRepository rolesRepository;

    @Autowired
    @Getter(value = AccessLevel.PROTECTED)
    @Setter
    private GroupsRepository groupsRepository;

    @Transactional(readOnly = true)
    @Override
    public DataResponse<RoleVO> findById(long id) {
        return super.findById(RoleVO.class, id, this.IGNORE_PROPERTIES);
    }

    @Transactional(readOnly = true)
    @Override
    public DataResponse<List<RoleVO>> findAll(int page, int size, String orderProp, Sort.Direction direction) {
        return super.findAll(RoleVO.class, page, size, orderProp, direction, this.IGNORE_PROPERTIES);
    }

    @Transactional
    @Override
    public DataResponse<RoleVO> add(RoleVO source) {
        return new DataResponse<RoleVO>().setResponse(super.conversionToValueObject(super.getRepository().saveAndFlush(new Roles(source.getRoleName())), RoleVO.class, this.IGNORE_PROPERTIES));
    }

    @Transactional
    @Override
    public boolean add(List<RoleVO> sourceList) {
        return false;
    }

    @Transactional
    @Override
    public DataResponse<RoleVO> update(long id, Map<String, Object> properties) throws AuthRestBusinessException {
        return super.update(RoleVO.class, id, properties, this.IGNORE_PROPERTIES);
    }

    @Transactional
    @Override
    public boolean update(Map<String, Object> properties, List<RoleVO> sourceList) {
        return false;
    }

    @Transactional
    @Override
    public DataResponse<List<RoleVO>> findAll(String roleName, int page, int size, String orderProp, Sort.Direction direction) {
        DataResponse<List<RoleVO>> result = new DataResponse<>();

        Page<Roles> pageEntities;
        List<Roles> entities;
        // 只有size参数有效时才会进行分页查询
        if (size > 0) {
            String likeParam = "%" + roleName + "%";
            pageEntities = this.rolesRepository.findAllByRoleNameLike(likeParam, new PageRequest(page, size, direction, orderProp));
            entities = pageEntities.getContent();
            result.setPages(new DataPage(pageEntities.getTotalPages(), pageEntities.getTotalElements(), pageEntities.getNumber(), pageEntities.getSize(), pageEntities.isFirst(), pageEntities.isLast()));
        } else {
            entities = super.getRepository().findAll(new Sort(direction, orderProp));
        }
        List<RoleVO> resultList = new ArrayList<>();
        for (Roles entity : entities) {
            resultList.add(this.conversionToValueObject(entity, RoleVO.class, this.IGNORE_PROPERTIES));
        }
        result.setResponse(resultList);
        return result;
    }

    @Transactional
    @Override
    public DataResponse<List<RoleVO>> findGroupInclusiveRole(Long groupId) throws AuthRestBusinessException {
        Groups groupEntity = this.groupsRepository.findOne(groupId);
        if (ObjectUtils.isEmpty(groupEntity))
            throw new AuthRestBusinessException("无法根据主键ID（" + groupId + "）查询到对应的用户组实体对象信息！");
        List<Roles> roleList = groupEntity.getRoles();
        return new DataResponse<List<RoleVO>>().setResponse(super.conversionToValueObject(roleList, RoleVO.class, this.IGNORE_PROPERTIES));
    }

    @Transactional
    @Override
    public DataResponse<List<RoleVO>> findGroupExclusiveRole(Long groupId) throws AuthRestBusinessException {
        Groups groupEntity = this.groupsRepository.findOne(groupId);
        if (ObjectUtils.isEmpty(groupEntity))
            throw new AuthRestBusinessException("无法根据主键ID（" + groupId + "）查询到对应的用户组实体对象信息！");
        List<Roles> roleList = this.rolesRepository.queryGroupExclusiveRoles(groupId);
        return new DataResponse<List<RoleVO>>().setResponse(super.conversionToValueObject(roleList, RoleVO.class, this.IGNORE_PROPERTIES));
    }

    @Transactional
    @Override
    public DataResponse<List<RoleVO>> assignRole(Long groupId, Long... roleIds) throws AuthRestBusinessException {
        Groups groupEntity = this.groupsRepository.findOne(groupId);
        if (ObjectUtils.isEmpty(groupEntity))
            throw new AuthRestBusinessException("无法根据主键ID（" + groupId + "）查询到对应的用户组实体对象信息！");
        List<Roles> assignRoleList = this.rolesRepository.findAllByIdIn(roleIds);
        if (ObjectUtils.isEmpty(assignRoleList))
            throw new AuthRestBusinessException("无法根据参数" + Arrays.toString(roleIds) + "匹配到所有的角色信息，请确保需分配的角色信息正确！");
        List<Roles> groupHasRoles = groupEntity.getRoles();
        if (!ObjectUtils.isEmpty(groupHasRoles)) {
            for (Roles hasRole : groupHasRoles) {
                if (ArrayUtils.contains(roleIds, hasRole.getId()))
                    throw new AuthRestBusinessException("当前用户组已经拥有角色：" + hasRole.getRoleName() + "，角色主键ID值：" + hasRole.getId());
            }
        }
        groupEntity.getRoles().addAll(assignRoleList);
        Groups updatedGroup = this.groupsRepository.saveAndFlush(groupEntity);
        return new DataResponse<List<RoleVO>>().setResponse(super.conversionToValueObject(updatedGroup.getRoles(), RoleVO.class, this.IGNORE_PROPERTIES));
    }

    @Transactional
    @Override
    public DataResponse<List<RoleVO>> releaseRole(Long groupId, Long... roleIds) throws AuthRestBusinessException {
        Groups groupEntity = this.groupsRepository.findOne(groupId);
        if (ObjectUtils.isEmpty(groupEntity))
            throw new AuthRestBusinessException("无法根据主键ID（" + groupId + "）查询到对应的用户组实体对象信息！");
        if (ObjectUtils.isEmpty(groupEntity.getRoles()))
            throw new AuthRestBusinessException("当前用户组并未被分配任何角色！");
        List<Roles> assignRoleList = this.rolesRepository.findAllByIdIn(roleIds);
        if (ObjectUtils.isEmpty(assignRoleList))
            throw new AuthRestBusinessException("无法根据参数" + Arrays.toString(roleIds) + "匹配到所有的角色信息，请确保需解绑的角色信息正确！");
        List<Roles> needRemoveRoles = new ArrayList<>();
        for (Roles hasRole : groupEntity.getRoles()) {
            if (ArrayUtils.contains(roleIds, hasRole.getId()))
                needRemoveRoles.add(hasRole);
        }
        if (!CollectionUtils.isEmpty(needRemoveRoles)) {
            groupEntity.getRoles().removeAll(needRemoveRoles);
        }
        Groups updatedGroup = this.groupsRepository.saveAndFlush(groupEntity);
        return new DataResponse<List<RoleVO>>().setResponse(super.conversionToValueObject(updatedGroup.getRoles(), RoleVO.class, this.IGNORE_PROPERTIES));
    }
}
